package com.fantastic.web.util;

import com.alipay.api.*;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradePagePayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeWapPayResponse;
import com.fantastic.common.exception.AlipayException;
import com.fantastic.common.exception.enums.RespStatusInfo;
import com.fantastic.model.vo.zjs.OrderVo;
import com.fantastic.model.pojo.zjs.Orders;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * @author: rxx
 * @since: 2024/6/19 15:37
 * @description: alipay支付工具类
 */
public class AlipayPayUtil {

    /**
     * 填充alipay请求对象的异步响应地址和同步响应地址和model对象
     *
     * @param alipayRequest 网页和app支付的Request对象共同实现的接口，可接收AlipayTradePagePayRequest类和AlipayTradeAppPayRequest类
     * @param notifyUrl     支付宝响应异步地址（字符串）
     * @param returnUrl     支付宝响应同步地址（字符串）
     * @param alipayObject  网页和app支付的model对象的父类，可接收AlipayTradePagePayRequest类和AlipayTradeAppPayRequest类
     */
    protected static void setAlipayRequestInfo(AlipayRequest alipayRequest, String notifyUrl, String returnUrl, AlipayObject alipayObject) {
        //填充异步响应地址
        alipayRequest.setNotifyUrl(notifyUrl);
        //填充同步响应地址
        alipayRequest.setReturnUrl(returnUrl);
        //填充model
        alipayRequest.setBizModel(alipayObject);
        //设置app_token
//        appPayRequest.putOtherTextParam("app_auth_token",?);
    }


    /**
     * 填充网页支付参数model
     *
     * @param orders 订单对象
     */
    protected static AlipayTradePagePayModel setPageModel(Orders orders) {
        //创建web支付模型对象，用于设置参数
        AlipayTradePagePayModel pageModel = new AlipayTradePagePayModel();
        //设置订单号
        pageModel.setOutTradeNo(String.valueOf(orders.getOrderId()));
        //设置订单要支付的金额
        pageModel.setTotalAmount(String.valueOf(orders.getOrderPays()));
        //设置商品标题
        //model.setSubject();
        return pageModel;
    }

    /**
     * 填充app支付参数model
     *
     * @param orders 订单对象
     * @return
     */
    protected static AlipayTradeAppPayModel setAppModel(Orders orders) {
        //创建app支付模型对象，用于设置参数
        AlipayTradeAppPayModel appModel = new AlipayTradeAppPayModel();
        //设置订单号
        appModel.setOutTradeNo(String.valueOf(orders.getOrderId()));
        //设置订单要支付的金额
        appModel.setTotalAmount(String.valueOf(orders.getOrderPays()));
        return appModel;
    }

    /**
     * web支付生成订单GSON字符串
     *
     * @param alipayPageRequest Alipay订单对象
     * @param orders            订单对象
     */
    protected static void setPageBizContent(AlipayTradePagePayRequest alipayPageRequest, OrderVo orders) {
        String body = "";
        alipayPageRequest.setBizContent("{\"out_trade_no\":\"" + orders.getOrderId() + "\","
                + "\"total_amount\":\"" + orders.getOrderPays() + "\","
                + "\"subject\":\"" + orders.getSubject() + "\","
                + "\"time_expire\":\"" + LocalDateTime.now() + "\","
                + "\"body\":\"" + body + "\","
                + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
    }

    /**
     * App支付生成订单GSON字符串
     *
     * @param alipayAppRequest Alipay请求对象
     * @param orders           订单对象
     * @return
     */
    protected static void setAppBizContent(AlipayTradeAppPayRequest alipayAppRequest, OrderVo orders) {
        String body = "";
        alipayAppRequest.setBizContent("{\"out_trade_no\":\"" + orders.getOrderId() + "\","
                + "\"total_amount\":\"" + orders.getOrderPays() + "\","
                + "\"subject\":\"" + orders.getSubject() + "\","
                + "\"time_expire\":\"" + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now().plusMinutes(30)) + "\","
                + "\"body\":\"" + body + "\"}");
    }

    /**
     * Wap支付生成订单GSON字符串
     *
     * @param alipayWapRequest Alipay请求对象
     * @param orders           订单对象
     * @return
     */
    protected static void setWapBizContent(AlipayTradeWapPayRequest alipayWapRequest, OrderVo orders) {
        String body = "";
        alipayWapRequest.setBizContent("{\"out_trade_no\":\"" + orders.getOrderId() + "\","
                + "\"total_amount\":\"" + orders.getOrderPays() + "\","
                + "\"subject\":\"" + orders.getSubject() + "\","
                + "\"time_expire\":\"" + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now().plusMinutes(30)) + "\","
                + "\"body\":\"" + orders.getAccountId() + "\"}");
    }

    /**
     * App执行发送支付请求
     *
     * @param alipayClient  支付宝客户端对象
     * @param appPayRequest app支付请求对象
     * @return 返回支付响应对象
     */
    protected static AlipayTradeAppPayResponse sdkExecute(AlipayClient alipayClient, AlipayTradeAppPayRequest appPayRequest) {
        try {
            //这里和普通的接口调用不同，使用的是sdkExecute
            return alipayClient.sdkExecute(appPayRequest);
        } catch (AlipayApiException e) {
            //抛出发送支付请求发起失败异常
            throw new AlipayException(RespStatusInfo.ALIPAY_REQ_ERROR);
        }
    }

    /**
     * 执行发送支付请求
     *
     * @param alipayClient
     * @param payRequest
     * @return
     */
    protected static AlipayResponse pageExecute(AlipayClient alipayClient, AlipayRequest payRequest) {
        try {
            payRequest.setReturnUrl(AlipayInfo.RETURN_URL);
            payRequest.setNotifyUrl(AlipayInfo.NOTIFY_URL);
            return alipayClient.pageExecute(payRequest, "POST");
        } catch (AlipayApiException e) {
            //抛出发送支付请求发起失败异常
            throw new AlipayException(RespStatusInfo.ALIPAY_REQ_ERROR);
        }
    }

    /**
     * wap检查是否成功调用支付宝接口
     *
     * @param response wap端响应对象
     */
    protected static void isAppSuccess(AlipayTradeAppPayResponse response) {
        if (!response.isSuccess()) {
            //抛出支付调用失败异常
            throw new AlipayException(RespStatusInfo.ALIPAY_RES_FAIL);
        }
    }

    /**
     * app检查是否成功调用支付宝接口
     *
     * @param response app端响应对象
     */
    protected static void isWapSuccess(AlipayTradeWapPayResponse response) {
        if (!response.isSuccess()) {
            //抛出支付调用失败异常
            throw new AlipayException(RespStatusInfo.ALIPAY_RES_FAIL);
        }
    }

    /**
     * 将支付宝请求过来的参数进行解析封装。
     * 再次之前需要设置给支付宝设置目标响应的地址，也就是    setNotifyUrl()
     *
     * @param req
     * @return
     */
    public static Map<String, String> alipayParamResolve(HttpServletRequest req) {
        Map<String, String> params = new HashMap<>();
        Map<String, String[]> requestParams = req.getParameterMap();    // 获取支付宝沙箱回调得所有参数
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);

            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            //乱码解决 在有乱码时使用
            params.put(name, newString(valueStr));
        }
        return params;
    }

    /**
     * 进行验证签名
     *
     * @param params 解析好的支付宝请求过来的参数
     */
    public static void rsaCheckV1(Map<String, String> params) {
        try {
            //SDK验证签名
            if (!AlipaySignature.rsaCheckV1(params,
                    AlipayInfo.PUBLIC_KEY,
                    AlipayInfo.CHARSET,
                    AlipayInfo.SIGN_TYPE)) {
                //抛出无效签名
                throw new AlipayException(RespStatusInfo.ALIPAY_VOID_SECURITY);
            }
        } catch (AlipayApiException e) {
            //抛出验签异常状态
            throw new AlipayException(RespStatusInfo.ALIPAY_SECURITY_ERROR);
        }
    }

    /**
     * 校验的状态
     * WAIT_BUYER_PAY（交易创建，等待买家付款）
     * TRADE_SUCCESS（交易支付成功，可退款）
     * TRADE_FINISHED（交易结束，不可退款）
     * TRADE_CLOSED（未付款交易超时关闭，或支付完成后全额退款）
     *
     * @param params 解析好的支付宝参数Map
     */
    public static String alipayStatusCheck(Map<String, String> params) {
        //获取订单状态。进行状态对应异常抛出
        switch (params.get(AlipayKey.TRADE_STATUS.getKeyValue())) {
            case "WAIT_BUYER_PAY":
                return "WAIT_BUYER_PAY";
            case "TRADE_SUCCESS": //支付成功返回支付金额
                return "success";
            case "TRADE_FINISHED":
                return "TRADE_FINISHED";
            case "TRADE_CLOSED":
                return "TRADE_CLOSED";
        }
        return "finis";
    }

    /**
     * 将支付宝请求的参数封装为Orders对象
     *
     * @param params
     */
    public static Orders getOrdersInfo(Map<String, String> params) {
        Orders orders = new Orders();
        //填充订单号
        orders.setAccountId(Integer.valueOf(params.get(AlipayKey.OUT_TRADE_NO)));
        //填充金额
        orders.setOrderPays(new BigDecimal(params.get(AlipayKey.TOTAL_AMOUNT)));
        return orders;
    }


    /**
     * 解决参数乱码
     *
     * @param value 要转换的目标值
     * @return 将值先转换为ISO-8859-1格式的字节，再将字节进行创建UTF-8的新String对象进行返回
     */
    public static String newString(String value) {
        try {
            return new String(value.getBytes(AlipayInfo.charsetName_ISO), AlipayInfo.CHARSET);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }
}
